//
//  Primitives.h
//  CodeKatas
//
//  Created by Viktor Lazarevich on 27-Feb-10.
//  Copyright 2010 Home. All rights reserved.
//

#import <Cocoa/Cocoa.h>

typedef struct _Money {
    int dollars;
    int cents;
} Money;

typedef enum {
	QuantityUnitPiece = 0,
	QuantityUnitPound = 1,
} QuantityUnit;

typedef struct _Quantity {
	double quantity;
	QuantityUnit unit;
} Quantity;

NS_INLINE Money MakeMoney(int dollars, int cents) {
	Money m;
	m.dollars = dollars + floor(cents / 100.0);
	m.cents = cents % 100;
	if (m.cents < 0) {
		m.cents += 100;
	}
	return m;
}

NS_INLINE Quantity MakeQuantityFromPounds(double pounds) {
	Quantity q;
	q.unit = QuantityUnitPound;
	q.quantity = pounds;
	return q;
}

NS_INLINE Quantity MakeQuantityFromPieces(int pieces) {
	Quantity q;
	q.unit = QuantityUnitPiece;
	q.quantity = pieces;
	return q;
}

NS_INLINE Money SumMoney(Money value1, Money value2) {
	return MakeMoney(value1.dollars + value2.dollars, value1.cents + value2.cents);
}

NS_INLINE Money SubtractMoney(Money value1, Money value2) {
	return MakeMoney(value1.dollars - value2.dollars, value1.cents - value2.cents);
}

NS_INLINE Quantity SumQuantity(Quantity value1, Quantity value2) {
	if (value1.unit != value2.unit) {
		@throw @"Different units of measure";
	}
	Quantity q;
	q.unit = value1.unit;
	q.quantity = value1.quantity + value2.quantity;
	return q;
}

NS_INLINE Quantity SubtractQuantity(Quantity value1, Quantity value2) {
	if (value1.unit != value2.unit) {
		@throw @"Different units of measure";
	}
	Quantity q;
	q.unit = value1.unit;
	q.quantity = value1.quantity - value2.quantity;
	return q;
}

NS_INLINE int TotalCents(Money money) {
	return money.dollars * 100 + money.cents;
}

NS_INLINE Money Multiply(Money money, Quantity quantity) {
	return MakeMoney(0, ceil(TotalCents(money) * quantity.quantity));
}

NS_INLINE Money MultiplyMoneyBy(Money money, double times) {
	return MakeMoney(0, ceil(TotalCents(money) * times));
}

NS_INLINE Quantity MultiplyQuantityBy(Quantity quantity, double times) {
	Quantity q;
	q.unit = quantity.unit;
	q.quantity = quantity.quantity * times;
	return q;
}

NS_INLINE Money Divide(Money money, Quantity quantity) {
	return MakeMoney(0, ceil(TotalCents(money) / quantity.quantity));
}

NS_INLINE Money DivideMoneyBy(Money money, double times) {
	return MakeMoney(0, ceil(TotalCents(money) / times));
}

NS_INLINE Quantity DivideQuantityBy(Quantity quantity, double times) {
	Quantity q;
	q.unit = quantity.unit;
	q.quantity = quantity.quantity / times;
	return q;
}

NS_INLINE double DivideMoney(Money value1, Money value2) {
	return TotalCents(value1) / (double)TotalCents(value2);
}

NS_INLINE double DivideQuantity(Quantity value1, Quantity value2) {
	if (value1.unit != value2.unit) {
		@throw @"Different units of measure";
	}

	return value1.quantity / value2.quantity;
}

NS_INLINE NSString * FormatMoney(Money money) {
	NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
	[numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
	[numberFormatter setCurrencySymbol:@"$"];
	[numberFormatter setCurrencyGroupingSeparator:@" "];
	[numberFormatter setCurrencyDecimalSeparator:@"."];
	[numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
	NSNumber *c = [NSNumber numberWithFloat:TotalCents(money)/100.0];
	
	return [numberFormatter stringFromNumber:c];
}

NS_INLINE NSString * FormatQuantity(Quantity quantity) {
	NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
	[numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
	switch (quantity.unit) {
		case QuantityUnitPiece:
			if (quantity.quantity == 1.0)
				[numberFormatter setFormat:@"0 piece"];
			else
				[numberFormatter setFormat:@"0 pieces"];
			break;
		case QuantityUnitPound:
			if (quantity.quantity == 1.0)
				[numberFormatter setFormat:@"0.#### pound"];
			else
				[numberFormatter setFormat:@"0.#### pounds"];
			break;
	}
	[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
	NSNumber *c = [NSNumber numberWithDouble:quantity.quantity];
	
	return [numberFormatter stringFromNumber:c];
}


